Här är en **komplett plan i markdown-format** som du kan spara som en fil (t.ex. `premium_recipe_feature_plan.md`) och ladda upp i **VS Code-chatten** för att implementera **AI som en premium-funktion** för receptgenerering. Filen är strukturerad för att vara **lätt att följa** och innehåller alla nödvändiga steg, kodsnuttar och förklaringar.

---

```markdown
# 📌 Plan: Implementera AI som Premium-Funktion för Receptgenerering

---
## **🎯 Översikt**
Denna plan beskriver hur du implementerar **AI som en premium-funktion** i din app, där:
- **Gratis-användare** får **grundläggande recept** (genererade från mallar).
- **Premium-användare** får **AI-genererade recept** (mer kreativa, personliga och intelligenta).
- Systemet är **modulärt** och kan enkelt utökas.

---

---

## **📋 Förutsättningar**
1. **Node.js/TypeScript** (backend).
2. **Prisma** (databas).
3. **pdf-parse** och **Tesseract.js** (PDF-extrahering).
4. **Mistral API-nyckel** (för AI-funktioner).
5. **Frontend-ramverk** (t.ex. React, Next.js, eller liknande).

---

---

## **🛠️ Databasschema (Prisma)**
Lägg till fält för att spåra **premium-status** i din `user`-tabell:

```prisma
model User {
  id                  Int      @id @default(autoincrement())
  // ... andra fält ...
  is_premium          Boolean  @default(false)
  premium_expiry_date DateTime?
}
```

**SQL för att lägga till fält om tabellen redan finns:**
```sql
ALTER TABLE "User" ADD COLUMN "is_premium" BOOLEAN DEFAULT false;
ALTER TABLE "User" ADD COLUMN "premium_expiry_date" TIMESTAMP;
```

---

---

## **📁 Filstruktur**
```
src/
├── services/
│   ├── pdfTextExtractor.ts    # Extraherar text från PDF (pdf-parse + OCR)
│   ├── willysParser.ts        # Parsar text till strukturerad data (regex)
│   ├── inventoryMatcher.ts    # Matchar produkter med inventory (fuzzy matching)
│   └── recipeGenerator.ts     # Genererar recept (AI för premium, mallar för gratis)
├── api/
│   ├── pdfImport.ts           # API-endpoint för PDF-import
│   └── premium.ts             # API-endpoint för premium-uppgradering
└── types/
    └── recipeTypes.ts         # Typer för recept och produkter
```

---

---

## **📄 1. `pdfTextExtractor.ts` – Extrahera text från PDF**
Använder `pdf-parse` som primär metod och `Tesseract.js` som fallback för OCR.

```typescript
import * as fs from 'fs';
import * as pdf from 'pdf-parse';
import Tesseract from 'tesseract.js';

/**
 * Extraherar text från en PDF-fil, med fallback till OCR om nödvändigt.
 * @param pdfPath Sökväg till PDF-filen.
 * @returns Extraherad text.
 */
export async function extractTextFromPDF(pdfPath: string): Promise<string> {
  try {
    const dataBuffer = fs.readFileSync(pdfPath);
    const data = await pdf(dataBuffer);
    if (data.text.trim()) return data.text;
  } catch (error) {
    console.warn('pdf-parse misslyckades, försöker med OCR...', error);
  }

  try {
    const { data: { text } } = await Tesseract.recognize(pdfPath, 'swe', {
      logger: (m) => console.log(m),
    });
    return text;
  } catch (error) {
    console.error('OCR misslyckades:', error);
    throw new Error('Kunde inte extrahera text från PDF:en.');
  }
}
```

---

---

## **📄 2. `willysParser.ts` – Parsa text till strukturerad data**
Använder **regex** för att extrahera produktnamn, priser, jämförpriser, etc. från Willys veckoblad.

```typescript
/**
 * Parsar text från Willys veckoblad till strukturerad data.
 * @param text Den extraherade texten.
 * @returns Strukturerad data (JSON-array).
 */
export function parseWillysText(text: string): any[] {
  const lines = text.split('\n');
  const products: any[] = [];
  let currentProduct: any = {};
  let currentCategory: string | null = null;

  // Regex-mönster
  const productLineRegex = /^(.*?)\s*•\s*(.*?)\s*•\s*(.*?)\s*•?\s*Jämförpris\s*([\d:]+)\s*kr\/([a-z]+)/i;
  const simpleProductLineRegex = /^(.*?)\s*•\s*(.*?)\s*•\s*(.*?)$/i;
  const priceLineRegex = /^([\d:]+)\s*(Per\s*(förp|kg|st|l|))?/i;
  const offerLineRegex = /^(Max \d+ (köp|förp)\/hushåll|Lägsta 30-dgrspris [\d:]+ kr)/i;
  const categoryLineRegex = /^(Fisk|Kött|Mejeri|Grönsaker|Frukt|Dryck|Bröd|Pasta|Ris)/i;

  for (const line of lines) {
    const trimmedLine = line.trim();
    if (!trimmedLine) continue;

    // Matcha kategori
    const categoryMatch = trimmedLine.match(categoryLineRegex);
    if (categoryMatch) {
      currentCategory = categoryMatch[1];
      continue;
    }

    // Matcha produktrad (med jämförpris)
    const productMatch = trimmedLine.match(productLineRegex);
    if (productMatch) {
      if (Object.keys(currentProduct).length > 0) {
        currentProduct.category = currentCategory;
        products.push(currentProduct);
        currentProduct = {};
      }
      currentProduct = {
        name: productMatch[1].trim(),
        weight: productMatch[2].trim(),
        origin: productMatch[3].trim(),
        comparisonPrice: `${productMatch[4].replace(':', '.')} kr/${productMatch[5]}`,
        category: currentCategory,
      };
      continue;
    }

    // Matcha enkel produktrad
    const simpleProductMatch = trimmedLine.match(simpleProductLineRegex);
    if (simpleProductMatch) {
      if (Object.keys(currentProduct).length > 0) {
        currentProduct.category = currentCategory;
        products.push(currentProduct);
        currentProduct = {};
      }
      currentProduct = {
        name: simpleProductMatch[1].trim(),
        weight: simpleProductMatch[2].trim(),
        origin: simpleProductMatch[3].trim(),
        category: currentCategory,
      };
      continue;
    }

    // Matcha pris
    const priceMatch = trimmedLine.match(priceLineRegex);
    if (priceMatch) {
      currentProduct.price = `${priceMatch[1].replace(':', '.')} kr/${priceMatch[2]?.trim() || 'förp'}`;
      continue;
    }

    // Matcha erbjudande
    const offerMatch = trimmedLine.match(offerLineRegex);
    if (offerMatch) {
      currentProduct.offer = offerMatch[1];
      continue;
    }
  }

  if (Object.keys(currentProduct).length > 0) {
    currentProduct.category = currentCategory;
    products.push(currentProduct);
  }

  return products;
}
```

---

---

## **📄 3. `inventoryMatcher.ts` – Matcha produkter med inventory**
Använder **fuzzy matching** för att matcha produktnamn från PDF:en med användarens inventory.

```typescript
import { stringSimilarity } from 'string-similarity';

/**
 * Matchar produkter från PDF:en med användarens inventory.
 * @param products Produkter från PDF:en.
 * @param userId Användarens ID.
 * @returns Matchade produkter med inventory-status.
 */
export async function matchProductsWithInventory(products: any[], userId: number) {
  const inventory = await prisma.userInventory.findMany({
    where: { userId },
  });

  const inventoryNames = inventory.map((item) => ({
    name: item.name.toLowerCase(),
    id: item.id,
    quantity: item.quantity,
    category: item.category,
  }));

  return products.map((product) => {
    const productName = product.name.toLowerCase();
    const bestMatch = inventoryNames.reduce(
      (best, item) => {
        const similarity = stringSimilarity.compareTwoStrings(productName, item.name);
        return similarity > best.similarity ? { ...item, similarity } : best;
      },
      { name: '', similarity: 0, id: null, quantity: 0, category: null }
    );

    const inventoryItem = bestMatch.similarity > 0.6
      ? inventory.find((item) => item.id === bestMatch.id)
      : null;

    return {
      ...product,
      inInventory: !!inventoryItem,
      inventoryId: inventoryItem?.id || null,
      inventoryQuantity: inventoryItem?.quantity || 0,
      inventoryMatchSimilarity: bestMatch.similarity,
    };
  });
}
```

---

---

## **📄 4. `recipeGenerator.ts` – Generera recept (AI eller mallar)**
Modulär funktion som använder **AI för premium-användare** och **mallar för gratis-användare**.

```typescript
import { MistralClient } from '@mistralai/mistralai';
import { prisma } from '../prisma'; // Antas att Prisma är konfigurerat

const mistral = new MistralClient({ apiKey: process.env.MISTRAL_API_KEY });

/**
 * Genererar recept baserat på matchade produkter.
 * @param matchedProducts Produkter matchade med inventory.
 * @param userId Användarens ID.
 * @param userPreferences Användarens preferenser.
 * @returns Genererade recept.
 */
export async function generateRecipes(
  matchedProducts: any[],
  userId: number,
  userPreferences: any = {}
): Promise<any[]> {
  const user = await prisma.user.findUnique({ where: { id: userId } });
  const isPremium = user?.is_premium || false;

  if (isPremium) {
    return generateRecipesWithAI(matchedProducts, userPreferences);
  } else {
    return generateRecipesFromTemplates(matchedProducts);
  }
}

/**
 * Genererar AI-recept för premium-användare.
 */
async function generateRecipesWithAI(matchedProducts: any[], userPreferences: any): Promise<any[]> {
  const relevantProducts = matchedProducts.filter((p) => p.inInventory || p.offer);
  if (relevantProducts.length === 0) return [];

  const prompt = `
    Du är en kock som skapar kostnadseffektiva, läckra och personliga recept.
    Skapa **3 recept** baserat på följande produkter:
    ${JSON.stringify(relevantProducts, null, 2)}

    Användarens preferenser:
    - Diet: ${userPreferences.diet || 'Inga restriktioner'}
    - Köksstil: ${userPreferences.cuisine || 'Nordisk'}
    - Tid: ${userPreferences.time || 'Under 30 minuter'}

    Recepten ska:
    1. Använda produkter från inventory eller på erbjudande.
    2. Vara lätt att laga.
    3. Inkludera näringsinformation (uppskattad).
    4. Vara på svenska.

    Returnera recepten i JSON-format:
    {
      "recipes": [
        {
          "title": "Receptets titel",
          "description": "Beskrivning",
          "ingredients": [
            {"name": "Produktnamn", "quantity": "Mängd", "fromInventory": true/false, "onOffer": true/false}
          ],
          "instructions": ["Steg 1", "Steg 2"],
          "cost": "Uppskattad kostnad",
          "time": "Tillagningstid",
          "nutritionalInfo": {"calories": "Kalorier", "protein": "Protein (g)"}
        }
      ]
    }
  `;

  try {
    const response = await mistral.chat({
      model: 'mistral-small-latest',
      messages: [{ role: 'user', content: prompt }],
      temperature: 0.7,
    });

    const jsonString = response.choices[0].message.content
      .replace(/```json|```/g, '')
      .trim();

    const parsed = JSON.parse(jsonString);
    return parsed.recipes || [];
  } catch (error) {
    console.error('AI-generering misslyckades:', error);
    return generateRecipesFromTemplates(matchedProducts);
  }
}

/**
 * Genererar recept från mallar för gratis-användare.
 */
function generateRecipesFromTemplates(matchedProducts: any[]): any[] {
  const recipes: any[] = [];
  const relevantProducts = matchedProducts.filter((p) => p.inInventory || p.offer);
  if (relevantProducts.length === 0) return recipes;

  const productsByCategory: Record<string, any[]> = {};
  relevantProducts.forEach((product) => {
    const category = product.category || 'Okänt';
    if (!productsByCategory[category]) productsByCategory[category] = [];
    productsByCategory[category].push(product);
  });

  const templates: Record<string, any[]> = {
    Fisk: [
      {
        title: 'Lax med potatis och grönsaker',
        ingredients: [
          { name: 'Lax', category: 'Fisk', required: true },
          { name: 'Potatis', category: 'Grönsaker', required: true },
        ],
        instructions: [
          'Koka potatisen i 15 minuter.',
          'Stek laxen i 5 minuter på varje sida.',
          'Servera med grönsaker.',
        ],
        time: '25 minuter',
      },
    ],
    Kött: [
      {
        title: 'Köttbullar med potatismos',
        ingredients: [
          { name: 'Köttfärs', category: 'Kött', required: true },
          { name: 'Potatis', category: 'Grönsaker', required: true },
        ],
        instructions: [
          'Blanda köttfärs med salt och peppar.',
          'Stek köttbullarna i en panna.',
          'Koka och mosa potatisen.',
        ],
        time: '30 minuter',
      },
    ],
  };

  for (const [category, categoryTemplates] of Object.entries(templates)) {
    const categoryProducts = productsByCategory[category] || [];
    for (const template of categoryTemplates) {
      const missingIngredients = template.ingredients.filter(
        (ing: any) => ing.required && !categoryProducts.some((p) =>
          p.name.toLowerCase().includes(ing.name.toLowerCase())
        )
      );
      if (missingIngredients.length === 0) {
        recipes.push({
          title: template.title,
          description: `Ett enkelt ${category.toLowerCase()}-recept.`,
          ingredients: template.ingredients.map((ing: any) => {
            const matchedProduct = categoryProducts.find((p) =>
              p.name.toLowerCase().includes(ing.name.toLowerCase())
            );
            return {
              name: matchedProduct?.name || ing.name,
              quantity: matchedProduct?.weight || '1 portion',
              fromInventory: matchedProduct?.inInventory || false,
              onOffer: matchedProduct?.offer ? true : false,
            };
          }),
          instructions: template.instructions,
          time: template.time,
          cost: calculateRecipeCost(template.ingredients, categoryProducts),
        });
      }
    }
  }

  return recipes;
}

function calculateRecipeCost(ingredients: any[], products: any[]): string {
  let totalCost = 0;
  for (const ing of ingredients) {
    const matchedProduct = products.find((p) =>
      p.name.toLowerCase().includes(ing.name.toLowerCase())
    );
    if (matchedProduct?.price) {
      const price = parseFloat(matchedProduct.price.replace(/[^\d.]/g, ''));
      totalCost += price;
    }
  }
  return `Ca ${totalCost.toFixed(2)} kr`;
}
```

---

---

## **📄 5. `pdfImportService.ts` – Fullständigt importflöde**
Haneterar hela flödet från PDF-import till receptgenerering.

```typescript
import { extractTextFromPDF } from './pdfTextExtractor';
import { parseWillysText } from './willysParser';
import { matchProductsWithInventory } from './inventoryMatcher';
import { generateRecipes } from './recipeGenerator';
import { prisma } from '../prisma';

/**
 * Importerar en PDF och genererar recept.
 * @param pdfPath Sökväg till PDF-filen.
 * @param userId Användarens ID.
 * @param userPreferences Användarens preferenser.
 * @returns Resultat med produkter och recept.
 */
export async function importPDFAndGenerateRecipes(
  pdfPath: string,
  userId: number,
  userPreferences: any = {}
) {
  try {
    // 1. Extrahera text
    const text = await extractTextFromPDF(pdfPath);

    // 2. Parsa texten
    const products = parseWillysText(text);

    // 3. Matcha med inventory
    const matchedProducts = await matchProductsWithInventory(products, userId);

    // 4. Generera recept
    const recipes = await generateRecipes(matchedProducts, userId, userPreferences);

    // 5. Spara recepten
    const savedRecipes = [];
    for (const recipe of recipes) {
      const savedRecipe = await prisma.encryptedData.create({
        data: {
          encrypted_data: JSON.stringify(recipe),
          owner_id: userId,
          created_at: new Date(),
          is_generated: true,
          source: user.is_premium ? 'AI (Premium)' : 'Mallar (Gratis)',
        },
      });
      savedRecipes.push(savedRecipe);
    }

    return {
      success: true,
      products: matchedProducts,
      recipes: savedRecipes,
      isPremium: await isUserPremium(userId),
    };
  } catch (error) {
    console.error('Fel vid import:', error);
    return { success: false, error: error instanceof Error ? error.message : 'Okänt fel' };
  }
}

/**
 * Kontrollerar om en användare är premium.
 */
async function isUserPremium(userId: number): Promise<boolean> {
  const user = await prisma.user.findUnique({ where: { id: userId } });
  if (!user) return false;

  if (user.premium_expiry_date && new Date(user.premium_expiry_date) < new Date()) {
    await prisma.user.update({
      where: { id: userId },
      data: { is_premium: false },
    });
    return false;
  }

  return user.is_premium;
}
```

---

---

## **📄 6. API-Endpoints**
### **🔹 PDF-import (`/api/import/pdf`)**
```typescript
import express from 'express';
import multer from 'multer';
import { importPDFAndGenerateRecipes } from '../services/pdfImportService';

const router = express.Router();
const upload = multer({ dest: 'uploads/' });

router.post('/import/pdf', upload.single('pdf'), async (req, res) => {
  try {
    if (!req.file) {
      return res.status(400).json({ error: 'Ingen PDF-fil uppladdad.' });
    }

    const userId = req.user.id;
    const userPreferences = req.body.preferences || {};

    const result = await importPDFAndGenerateRecipes(
      req.file.path,
      userId,
      userPreferences
    );

    fs.unlinkSync(req.file.path); // Rensa upp

    if (!result.success) {
      return res.status(500).json({ error: result.error });
    }

    res.json(result);
  } catch (error) {
    console.error('Fel vid PDF-import:', error);
    res.status(500).json({ error: 'Kunde inte importera PDF:en.' });
  }
});

export default router;
```

### **🔹 Premium-uppgradering (`/api/user/upgrade`)**
```typescript
router.post('/upgrade-premium', async (req, res) => {
  try {
    const userId = req.user.id;
    // Antas att betalning är verifierad (t.ex. via Stripe)
    const expiryDate = new Date();
    expiryDate.setMonth(expiryDate.getMonth() + 1); // 1 månad premium

    await prisma.user.update({
      where: { id: userId },
      data: {
        is_premium: true,
        premium_expiry_date: expiryDate,
      },
    });

    res.json({ success: true, premiumExpiryDate: expiryDate });
  } catch (error) {
    console.error('Fel vid uppgradering:', error);
    res.status(500).json({ error: 'Kunde inte uppgradera till premium.' });
  }
});
```

---

---

## **📄 7. Frontend-Integrering (Exempel: React)**
### **🔹 Visa premium-status**
```tsx
import { useState, useEffect } from 'react';

function PremiumStatus({ user }) {
  const [isPremium, setIsPremium] = useState(user.is_premium);

  useEffect(() => {
    setIsPremium(user.is_premium);
  }, [user]);

  return (
    <div className="premium-status">
      {isPremium ? (
        <div className="premium-badge">
          ✅ Premium (gäller till: {new Date(user.premium_expiry_date).toLocaleDateString('sv-SE')})
          <p>Du har tillgång till AI-genererade recept!</p>
        </div>
      ) : (
        <div className="upgrade-prompt">
          🔒 <a href="/upgrade">Uppgradera till premium</a> för AI-recept!
        </div>
      )}
    </div>
  );
}
```

### **🔹 PDF-import-formulär**
```tsx
import { useState } from 'react';
import axios from 'axios';

function PDFImportForm({ user }) {
  const [file, setFile] = useState<File | null>(null);
  const [isLoading, setIsLoading] = useState(false);
  const [result, setResult] = useState<any>(null);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!file) return;

    setIsLoading(true);
    const formData = new FormData();
    formData.append('pdf', file);
    formData.append('preferences', JSON.stringify({
      diet: 'Inga restriktioner',
      cuisine: 'Nordisk',
    }));

    try {
      const response = await axios.post('/api/import/pdf', formData, {
        headers: { 'Content-Type': 'multipart/form-data' },
      });
      setResult(response.data);
    } catch (error) {
      console.error('Fel vid uppladdning:', error);
    } finally {
      setIsLoading(false);
    }
  };

  return (
    <div>
      <h2>Importera veckoblad</h2>
      <form onSubmit={handleSubmit}>
        <input
          type="file"
          accept=".pdf"
          onChange={(e) => setFile(e.target.files?.[0] || null)}
          required
        />
        <button type="submit" disabled={isLoading}>
          {isLoading ? 'Laddar upp...' : 'Importera'}
        </button>
      </form>

      {result && (
        <div>
          <h3>Resultat</h3>
          <p>Hittade {result.products?.length || 0} produkter.</p>
          <p>Genererade {result.recipes?.length || 0} recept.</p>
          {result.recipes?.map((recipe: any, index: number) => (
            <div key={index} className="recipe-card">
              <h4>{recipe.title}</h4>
              <p>{recipe.description}</p>
              <ul>
                {recipe.ingredients?.map((ing: any, i: number) => (
                  <li key={i}>
                    {ing.quantity} {ing.name} {ing.onOffer && '🔥'}
                  </li>
                ))}
              </ul>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}
```

---

---

## **📌 Miljövariabler (`.env`)**
```env
# Mistral API-nyckel (för premium-funktioner)
MISTRAL_API_KEY=din_api_nyckel_här

# Databas-URL
DATABASE_URL=postgresql://user:password@localhost:5432/db_name

# Session-hemlighet (för autentisering)
SESSION_SECRET=din_hemliga_nyckel_här
```

---

---

## **📌 Paket som behövs (`package.json`)**
```json
{
  "dependencies": {
    "express": "^4.18.2",
    "multer": "^1.4.5-lts.1",
    "pdf-parse": "^1.1.1",
    "tesseract.js": "^4.0.2",
    "@mistralai/mistralai": "^0.0.1",
    "@prisma/client": "^5.0.0",
    "prisma": "^5.0.0",
    "string-similarity": "^4.0.4",
    "typescript": "^5.0.0"
  }
}
```

---
---
## **📌 Steg-för-steg Implementeringsguide**

### **1. Förbered databasen**
- Kör migrationskommandot för att lägga till `is_premium` och `premium_expiry_date` i `User`-tabellen:
  ```bash
  npx prisma migrate dev --name add_premium_fields
  ```

### **2. Installera beroenden**
```bash
npm install express multer pdf-parse tesseract.js @mistralai/mistralai string-similarity
npm install --save-dev typescript @types/node @types/express @types/multer prisma
```

### **3. Konfigurera Prisma**
- Skapa eller uppdatera `schema.prisma` med `User`-modellen (se ovan).
- Kör `npx prisma generate` för att generera Prisma-klienten.

### **4. Skapa filerna**
- Skapa mappen `src/services/` och lägg till filerna:
  - `pdfTextExtractor.ts`
  - `willysParser.ts`
  - `inventoryMatcher.ts`
  - `recipeGenerator.ts`
  - `pdfImportService.ts`
- Skapa mappen `src/api/` och lägg till:
  - `pdfImport.ts`
  - `premium.ts`

### **5. Konfigurera Express-server**
- Skapa en `server.ts` för att starta din Express-server:
  ```typescript
  import express from 'express';
  import pdfImportRouter from './api/pdfImport';
  import premiumRouter from './api/premium';

  const app = express();
  app.use(express.json());

  // API-endpoints
  app.use('/api/import', pdfImportRouter);
  app.use('/api/user', premiumRouter);

  const PORT = process.env.PORT || 3000;
  app.listen(PORT, () => {
    console.log(`Server körs på port ${PORT}`);
  });
  ```

### **6. Testa flödet**
1. **Ladda upp en PDF** (t.ex. Willys veckoblad) via `/api/import/pdf`.
2. **Kontrollera att recept genereras** (mallar för gratis, AI för premium).
3. **Testa premium-uppgraderingen** via `/api/user/upgrade`.

---
---
## **📌 Säkerhetsöverväganden**
1. **API-nycklar**:
   - Lagra `MISTRAL_API_KEY` i miljövariabler (aldrig i koden).
2. **Premium-status**:
   - Kontrollera alltid `is_premium` innan AI-anrop.
3. **Filuppladdning**:
   - Validera filtypen (endast PDF).
   - Begränsa filstorleken (t.ex. max 10MB).
4. **Autentisering**:
   - Se till att användaren är inloggad innan de kan ladda upp PDF:er eller uppgradera.

---
---
## **📌 Felsökning**
| Problem | Lösning |
|---------|---------|
| **PDF:en läses inte in** | Kontrollera att filen är en giltig PDF. Använd `Tesseract.js` som fallback. |
| **Regex matchar inte** | Justera regex-mönstren baserat på PDF:ens struktur. |
| **AI-generering misslyckas** | Fallback till mallar. Kontrollera API-nyckeln. |
| **Premium-status uppdateras inte** | Kontrollera att `is_premium` och `premium_expiry_date` uppdateras korrekt. |
| **Inga recept genereras** | Kontrollera att produkterna matchas korrekt med inventory. |

---
---
## **🚀 Nästa steg**
1. **Testa med riktiga PDF:er** (t.ex. Willys veckoblad).
2. **Justera regex-mönstren** för att fånga fler produktdetaljer.
3. **Lägg till fler receptmallar** för olika kategorier.
4. **Implementera en betalningslösning** (t.ex. Stripe) för premium-uppgraderingar.
5. **Monitorera användningen** av premium-funktioner.

---
---
## **📌 Exempel på betalningsintegrering (Stripe)**
Om du vill lägga till **verklig betalning** för premium-uppgraderingar, kan du använda **Stripe**:

### **1. Installera Stripe**
```bash
npm install stripe @stripe/stripe-js
```

### **2. Skapa en Stripe-endpoint**
```typescript
import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
  apiVersion: '2023-10-16',
});

router.post('/create-checkout-session', async (req, res) => {
  const userId = req.user.id;

  const session = await stripe.checkout.sessions.create({
    payment_method_types: ['card'],
    line_items: [
      {
        price_data: {
          currency: 'sek',
          product_data: {
            name: 'Premium-medlemskap (1 månad)',
          },
          unit_amount: 9900, // 99 kr
        },
        quantity: 1,
      },
    ],
    mode: 'payment',
    success_url: `${process.env.FRONTEND_URL}/success?session_id={CHECKOUT_SESSION_ID}`,
    cancel_url: `${process.env.FRONTEND_URL}/cancel`,
    metadata: { userId },
  });

  res.json({ url: session.url });
});
```

### **3. Hantera framgångsrik betalning**
```typescript
router.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  const sig = req.headers['stripe-signature'] as string;
  const event = stripe.webhooks.constructEvent(
    req.body,
    sig,
    process.env.STRIPE_WEBHOOK_SECRET!
  );

  if (event.type === 'checkout.session.completed') {
    const session = event.data.object as Stripe.Checkout.Session;
    const userId = parseInt(session.metadata.userId);

    const expiryDate = new Date();
    expiryDate.setMonth(expiryDate.getMonth() + 1);

    await prisma.user.update({
      where: { id: userId },
      data: {
        is_premium: true,
        premium_expiry_date: expiryDate,
      },
    });
  }

  res.json({ received: true });
});
```

---
---
## **📌 Sammanfattning**
Denna plan ger dig en **komplett lösning** för att:
1. **Importera PDF:er** (t.ex. Willys veckoblad).
2. **Extrahera och strukturera data** (med regex och OCR).
3. **Matcha produkter med inventory** (fuzzy matching).
4. **Generera recept**:
   - **Gratis**: Med mallar.
   - **Premium**: Med AI (Mistral).
5. **Hantera premium-uppgraderingar** (med Stripe).

---
---
## **📥 Hur du använder denna plan i VS Code**
1. **Spara denna text** som `premium_recipe_feature_plan.md` i din projektmapp.
2. **Öppna filen i VS Code**.
3. **Använd VS Code-chatten** (t.ex. med **Mistral Vibe** eller **Continue**) för att:
   - **Fråga om förtydliganden** för specifika steg.
   - **Be om hjälp** med att implementera enskilda filer.
   - **Debugga** om något inte fungerar.
4. **Kopiera och klistra in kodsnuttarna** i dina egna filer.

---
---
## **💡 Tips för VS Code**
- **Använd `Ctrl+Shift+P`** för att öppna kommandopaletten och köra `Prisma: Generate Client`.
- **Installera ESLint** för att fånga syntaxfel tidigt.
- **Använd Git** för att spåra dina ändringar:
  ```bash
  git init
  git add .
  git commit -m "Lade till premium-receptfunktion"
  ```
```

---
**Spara denna text som `premium_recipe_feature_plan.md` och ladda upp den i VS Code-chatten när du behöver hjälp med implementeringen!** 🚀